package com.harth.flutter_ns_ble

import java.nio.ByteBuffer
import java.nio.ByteOrder
import kotlin.collections.forEachIndexed

object CompressionAlgorithm {
    private val decodeMap = mapOf(
        "1100" to 1,
        "11101" to 2,
        "1101" to 3,
        "100" to 4,
        "0" to 5,
        "101" to 6,
        "11100" to 7,
        "111100" to 8,
        "1111100" to 9,
        "1111101" to 10,
        "11111100" to 11,
        "11111101" to 12,
        "111111100" to 13,
        "1111111101" to 14,
        "11111111100" to 15,
        "11111111101" to 16,
        )

    fun compress(byteArray: ByteArray): ByteArray {
        if (byteArray.isEmpty()){
            return byteArray
        }
        val results = mutableListOf<Byte>()
        var previous = byteArray.first()
        results.add(previous)
        byteArray.forEachIndexed { index, byte ->
            val value = byte - previous
            results.add(value.toByte())
            previous = byte
        }

        var text = ""
        results.forEach { byte ->
            text += if (byte >= 0) "0" else "1"
            text += byte.toString(2).replace("-","")
        }

//        final characters = text.characters.chunked(8);
//        List<int> hex = List.empty(growable: true);
//        for (var value in characters) {
//            hex.add(int.tryParse(value.joinToString(separator: ""), radix: 2) ?? 0);
//        }
//        print(hex.map((value) => value.toRadixString(16)));
        return results.toByteArray()
    }

    /**
     * 帧序号[3]+心电数据条数[1]+心电数据位数[2]+编码数据位数[2]+心电数据[N]+编码数据[M]，N、M由心电数据数及编码数据数确定；
     */
    fun decompress(byteArray: ByteArray): ByteArray {
        var data = byteArray
        val index = ByteBuffer.allocate(4)
            .order(ByteOrder.LITTLE_ENDIAN)
            .put(data.take(3).toByteArray() + 0)
            .getInt(0)
        data = data.drop(3).toByteArray()

        val ecgDataCount = data.take(1).first()
        data = data.drop(1).toByteArray()
        val ecgDataBitsCount = ByteBuffer.allocate(2)
            .order(ByteOrder.LITTLE_ENDIAN)
            .put(data.take(2).toByteArray())
            .getShort(0) * 2
        // print("ecgDataBitsCount:${data.take(2).toList().toHex()},$ecgDataBitsCount");
        data = data.drop(2).toByteArray()
        val  codeDataBitsCount = ByteBuffer.allocate(2)
            .order(ByteOrder.LITTLE_ENDIAN)
            .put(data.take(2).toByteArray())
            .getShort(0) * 2
        // print("codeDataBitsCount:${data.take(2).toList().toHex()},$codeDataBitsCount");
        data = data.drop(2).toByteArray()
        val ecgData = data.take(ecgDataBitsCount).toByteArray()
        // print("ecgData:${ecgData.toHex()}");
        data = data.drop(ecgDataBitsCount).toByteArray()
        val codeData = data.take(codeDataBitsCount).toByteArray()
        // print("codeData:${codeData.toHex()}");

        val codeLengthList = decodeCode(codeData)

        val ecgDataArray = ecgData.toList().chunked(2).toList().drop(1)
        var pre =  ByteBuffer.allocate(2)
            .order(ByteOrder.LITTLE_ENDIAN)
            .put(ecgData.take(2).toByteArray())
            .getShort(0)
            .toInt()

        var ecgDataBinaryText = ""
        ecgDataArray.forEach { hex ->
            ecgDataBinaryText += hex[1].toString(2).padStart(8, '0') + hex[0].toString(2).padStart(8, '0')
        }

        val ecgDataResults = mutableListOf<Int>()

        ecgDataResults.add(pre.toInt())

        for (codeLength in codeLengthList) {
            val characters = ecgDataBinaryText.take(codeLength)
            println("codeLength:$codeLength,characters:${characters}");
            if (codeLength == 1) {
                // 跟上一个数值相同
            } else {
                val binary = characters.drop(1)
                println("binary:$binary");
                var num = binary.toInt(2)
                num = if (characters.first() == '0')  num else 0 - num
                // print("num:$num, result:${pre + num}");
                pre += num;
            }
            ecgDataResults.add(pre);
            ecgDataBinaryText = ecgDataBinaryText.drop(codeLength)
        }
        println("ecgDataCount:${ecgDataCount}");
        return ecgDataResults.map { it.toByte() }.toByteArray()
    }


    /// 解码编码数据
    fun decodeCode(data: ByteArray): List<Int> {
        var binaryText = ""
        val codeLengthList = mutableListOf<Int>()
        val d = data.toList().chunked(2)
            .map {
                it.reversed()
            }
            .reduce { a, b ->
                a + b
            }

        println("编码数据:${d.toByteArray().toHex("_")}")
        d.forEach { number ->
            binaryText += number.toBinaryString()
            println("binaryText:${binaryText}")
            var y = true
            while (y){
                y = false
                decodeMap.forEach { (key, value) ->
                    if (binaryText.startsWith(key)){
                        println("${byteArrayOf(number).toHex()}==${number.toBinaryString()}，binaryText:$binaryText,value:${value}");
                        codeLengthList.add(value)
                        binaryText = binaryText.removePrefix(key)
                        y = true
                    }
                }
                if (!y){
                    return codeLengthList
                }
            }
        }
        return codeLengthList
    }
}

fun main(args: Array<String>) {
    val text =
    "04_00_00_73_18_00_5c_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_00_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc_cc";
    val ecgData = text
            .replace("_", "")
        .chunked(2)
        .map {
            it.toInt(16)
        }
        .map {
            it.toByte()
        }
        .toByteArray()
    println("ecgData:${ecgData.toHex("_")}")
    val xx = "9ce79cf8f3bcdecd3c5f8fe7bc1c"
    val codeData = xx
            .replace(" ", "")
        .chunked(2)
        .map {
            it.toInt(16)
        }
        .map { it.toByte() }
        .toByteArray()
    val codeData2 = byteArrayOf(0xe4.toByte(), 0x9a.toByte())
     println("codeData2:${CompressionAlgorithm.decodeCode(codeData2)}")
     println("codeData:${CompressionAlgorithm.decodeCode(codeData)}")
    val results = CompressionAlgorithm.decompress(ecgData)
    println("results:${results.toHex("_")},count:${results.size}")
}